/*
 * acooly.cn Inc.
 * Copyright (c) 2016 All Rights Reserved.
 * create by zhangpu 
 * date:2016年4月4日
 *
 */
package com.acooly.module.openapi.client.provider.yl.marshall;

import com.acooly.core.utils.Strings;
import com.acooly.core.utils.security.RSA;
import com.acooly.core.utils.validate.Validators;
import com.acooly.module.openapi.client.api.exception.ApiClientException;
import com.acooly.module.openapi.client.provider.yl.YlConstants;
import com.acooly.module.openapi.client.provider.yl.YlProperties;
import com.acooly.module.openapi.client.provider.yl.domain.YlApiMessage;
import com.acooly.module.openapi.client.provider.yl.domain.YlRequest;
import com.acooly.module.openapi.client.provider.yl.enums.YlServiceEnum;
import com.acooly.module.openapi.client.provider.yl.message.YlBatchDeductRequest;
import com.acooly.module.openapi.client.provider.yl.message.YlDeductQueryRequest;
import com.acooly.module.openapi.client.provider.yl.message.YlRealDeductRequest;
import com.acooly.module.openapi.client.provider.yl.message.YlbillDownloadRequest;
import com.acooly.module.safety.Safes;
import com.acooly.module.safety.key.KeyLoadManager;
import com.acooly.module.safety.signature.SignTypeEnum;
import com.acooly.module.safety.signature.SignerFactory;
import com.acooly.module.safety.support.CodecEnum;
import com.acooly.module.safety.support.KeyStoreInfo;

import org.springframework.beans.factory.annotation.Autowired;

import lombok.extern.slf4j.Slf4j;

import static com.acooly.module.openapi.client.provider.yl.utils.XmlHelper.buildPayReqMsg;

/**
 * @author
 */
@Slf4j
public class YlMarshallSupport {

    @Autowired
    protected YlProperties ylProperties;

    @Autowired
    protected SignerFactory signerFactory;

    @Autowired
    private KeyLoadManager keyStoreLoadManager;

    protected YlProperties getProperties() {
        return ylProperties;
    }

    protected String doMarshall(YlRequest source) {
        doVerifyParam(source);
        String reqMsg ="";
        //组装报文
        if(Strings.equals(YlServiceEnum.YL_REAL_DEDUCT.getKey(),source.getTrxCode())){
            YlRealDeductRequest request = (YlRealDeductRequest)source;
            reqMsg = buildPayReqMsg(request);
        }else if(Strings.equals(YlServiceEnum.YL_BATCH_DEDUCT.getKey(),source.getTrxCode())){
            YlBatchDeductRequest request = (YlBatchDeductRequest)source;
            reqMsg = buildPayReqMsg(request);
        }else if(Strings.equals(YlServiceEnum.YL_REAL_DEDUCT_QUERY.getKey(),source.getTrxCode())){
            YlDeductQueryRequest request = (YlDeductQueryRequest)source;
            reqMsg = buildPayReqMsg(request);
        }else if(Strings.equals(YlServiceEnum.YL_BILL_DOWNLOAD.getCode(),source.getTrxCode())){
            YlbillDownloadRequest request = (YlbillDownloadRequest)source;
            ylProperties.setFilePath(request.getFilePath());
            reqMsg = buildPayReqMsg(request);
        }
        ylProperties.setPartnerId(source.getPartnerId());
        log.debug("待签字符串:{}", reqMsg);
        return doSign(reqMsg, source);
    }


    /**
     * 校验参数
     *
     * @param source
     */
    protected void doVerifyParam(YlApiMessage source) {
        try {
            source.doCheck();
            Validators.assertJSR303(source);
        } catch (Exception e) {
            throw new ApiClientException(e.getMessage());
        }
    }

    protected void beforeMarshall(YlApiMessage message) {
        if(Strings.isBlank(message.getPartnerId())) {
            message.setPartnerId(getProperties().getPartnerId());
        }
    }

    /**
     * 签名 优先获取传进来的，如果传进来没有则用配置文件中的
     *
     * @param waitForSign
     * @param source
     * @return
     */
    protected String doSign(String waitForSign, YlRequest source) {
        KeyStoreInfo keyStoreInfo = getKeyStoreInfo(source.getPartnerId());
        String signMsg = "";
        //对帐签名串单独处理
        if(Strings.equals(YlServiceEnum.YL_BILL_DOWNLOAD.getCode(),source.getTrxCode())){
            //签名
            String signStr = Safes.getSigner(SignTypeEnum.Cert).sign(waitForSign, keyStoreInfo);
            YlbillDownloadRequest request = (YlbillDownloadRequest)source;
            String now = waitForSign.substring(waitForSign.lastIndexOf("|")+1);
            String param1 = "SETT_DATE=" + request.getPeriodNo();
            String param2 = "&SETT_NO=" + request.getSettNo();//01   02
            String param3 = "&SF_TYPE=" + request.getDsfFlag();//代收S 代付F
            String param4 = "&USER_NAME=" + request.getPartnerName();
            String param5 = "&MERCHANT_ID=" + request.getPartnerId();
            String param6 = "&REQ_TIME=" + now;
            String param7 = "&SIGNED_MSG=";//使用用户名对应的证书签名，签名内容为：清算日期，场次，用户名，商户号，请求时间
            String param = param1 + param2 + param3 + param4 + param5 + param6 + param7;
            String visitUrl = request.getVisitUrl() + param;
            signMsg = visitUrl += signStr;
        }else{
            //去掉多余的字符
            String strMsg = waitForSign.replaceAll("<SIGNED_MSG></SIGNED_MSG>", "");
            //签名
            String signStr = Safes.getSigner(SignTypeEnum.Cert).sign(strMsg, keyStoreInfo);
            //组装报文并返回
            signMsg = waitForSign.replaceAll("<SIGNED_MSG></SIGNED_MSG>", "<SIGNED_MSG>"+signStr+"</SIGNED_MSG>");
        }
        return signMsg;
    }

    /**
     * 获取keyStoreInfo
     *
     * @return
     */
    protected KeyStoreInfo getKeyStoreInfo(String parnerId) {
        KeyStoreInfo keyStoreInfo = new KeyStoreInfo();
        try {
            keyStoreInfo = keyStoreLoadManager.load(parnerId, YlConstants.PROVIDER_NAME);
        }catch (Exception e){
            log.info("商户partnerId={}密钥加载失败，启用配置文件密钥",parnerId);
            keyStoreInfo.setCertificateUri(ylProperties.getPublicCertPath());
            keyStoreInfo.setKeyStoreUri(ylProperties.getPrivateCertPath());
            keyStoreInfo.setKeyStorePassword(ylProperties.getPrivateCertPassword());
            keyStoreInfo.setPlainEncode("GBK");
            keyStoreInfo.setSignatureCodec(CodecEnum.HEX);
            keyStoreInfo.setKeyStoreType(RSA.KEY_STORE_PKCS12);
            keyStoreInfo.loadKeys();
        }

        return keyStoreInfo;
    }





}
